﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Web.Mvc.Ajax;
using System.Web.UI;
using System.Linq.Expressions;

using Microsoft.Practices.Unity;

using ERPStore.Extensions;
using ERPStore.Web.Html;
using ERPStore.Web.Routing;
using ERPStore.Web.Extensions;

using CloudSoft.Extensions;

namespace ERPStore.Localization.Html
{
	public static class LocalizationExtensions
	{
		/// <summary>
		/// Traduction d'un terme pour la globalité du site
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <param name="key">The key.</param>
		/// <param name="defaultContent">The default content.</param>
		/// <returns></returns>
		public static string GlobalLocalize(this HtmlHelper helper, string key, string defaultContent)
		{
			var language = helper.GetCurrentLanguage();
			var path = "App_GlobalResources";
			var localizationService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.ILocalizationService>();
			var token = helper.ViewContext.HttpContext.Request["translate"];
			return localizationService.GetLocalizedContent(path, language, token, key, defaultContent, ERPStore.Models.LocalizedContentType.Label);
		}

		/// <summary>
		/// Traduction d'un terme lorsqu'il se trouve dans un controle utilisateur
		/// </summary>
		/// <param name="viewUserControl">The view user control.</param>
		/// <param name="key">The key.</param>
		/// <param name="defaultContent">The default content.</param>
		/// <returns></returns>
		public static string Localize(this System.Web.Mvc.ViewUserControl viewUserControl, string key, string defaultContent)
		{
			return Localize(viewUserControl, key, defaultContent, ERPStore.Models.LocalizedContentType.Label);
		}

		/// <summary>
		/// Traduction de l'attribut d'un terme lorsqu'il se trouve dans l'attribut d'un element html
		/// </summary>
		/// <param name="viewUserControl">The view user control.</param>
		/// <param name="key">The key.</param>
		/// <param name="defaultContent">The default content.</param>
		/// <returns></returns>
		public static string LocalizeAttribute(this System.Web.Mvc.ViewUserControl viewUserControl, string key, string defaultContent)
		{
			return Localize(viewUserControl, key, defaultContent, ERPStore.Models.LocalizedContentType.Attribute);
		}

		public static string LocalizeImageSource(this System.Web.Mvc.ViewUserControl viewUserControl, string key, string defaultContent)
		{
			return Localize(viewUserControl, key, defaultContent, ERPStore.Models.LocalizedContentType.ImageSource);
		}

		private static string Localize(this System.Web.Mvc.ViewUserControl viewUserControl, string key, string defaultContent, ERPStore.Models.LocalizedContentType contentType)
		{
			var language = viewUserControl.Html.GetCurrentLanguage();
			var path = GetVirtualPath(viewUserControl);
			var localizationService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.ILocalizationService>();
			var token = viewUserControl.ViewContext.HttpContext.Request["translate"];
			return localizationService.GetLocalizedContent(path, language, token, key, defaultContent, contentType);
		}

		/// <summary>
		/// Traduction d'un terme lorsqu'il se trouve dans une page
		/// </summary>
		/// <param name="viewPage">The view page.</param>
		/// <param name="key">The key.</param>
		/// <param name="defaultContent">The default content.</param>
		/// <returns></returns>
		public static string Localize(this System.Web.Mvc.ViewPage viewPage, string key, string defaultContent)
		{
			return Localize(viewPage, key, defaultContent, ERPStore.Models.LocalizedContentType.Label);
		}

		/// <summary>
		/// Traduction d'un terme losqu'il se trouve dans l'attribut d'un element html se trouvant dans une page
		/// </summary>
		/// <param name="viewPage">The view page.</param>
		/// <param name="key">The key.</param>
		/// <param name="defaultContent">The default content.</param>
		/// <returns></returns>
		public static string LocalizeAttribute(this System.Web.Mvc.ViewPage viewPage, string key, string defaultContent)
		{
			return Localize(viewPage, key, defaultContent, ERPStore.Models.LocalizedContentType.Attribute);
		}

		/// <summary>
		/// Traduction d'une url source d'une image
		/// </summary>
		/// <param name="viewPage">The view page.</param>
		/// <param name="key">The key.</param>
		/// <param name="defaultContent">The default content.</param>
		/// <returns></returns>
		public static string LocalizeImageSource(this System.Web.Mvc.ViewPage viewPage, string key, string defaultContent)
		{
			return Localize(viewPage, key, defaultContent, ERPStore.Models.LocalizedContentType.ImageSource);
		}

		private static string Localize(this System.Web.Mvc.ViewPage viewPage, string key, string defaultContent, ERPStore.Models.LocalizedContentType contentType)
		{
			var language = viewPage.Html.GetCurrentLanguage();
			var path = GetVirtualPath(viewPage);
			var localizationService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.ILocalizationService>();
			var token = viewPage.ViewContext.HttpContext.Request["translate"];
			return localizationService.GetLocalizedContent(path, language, token, key, defaultContent, contentType);
		}

		/// <summary>
		/// Traduction d'un terme losqu'il se trouve dans une page master
		/// </summary>
		/// <param name="master">The master.</param>
		/// <param name="key">The key.</param>
		/// <param name="defaultContent">The default content.</param>
		/// <returns></returns>
		public static string Localize(this ViewMasterPage master, string key, string defaultContent)
		{
			return Localize(master, key, defaultContent, ERPStore.Models.LocalizedContentType.Label);
		}

		/// <summary>
		/// Traduction d'un terme lorsqu'il se trouve dans l'attribut d'un element de page se trouvant dans une page master
		/// </summary>
		/// <param name="master">The master.</param>
		/// <param name="key">The key.</param>
		/// <param name="defaultContent">The default content.</param>
		/// <returns></returns>
		public static string LocalizeAttribute(this ViewMasterPage master, string key, string defaultContent)
		{
			return Localize(master, key, defaultContent, ERPStore.Models.LocalizedContentType.Attribute);
		}

		public static string LocalizeImageSource(this ViewMasterPage master, string key, string defaultContent)
		{
			return Localize(master, key, defaultContent, ERPStore.Models.LocalizedContentType.ImageSource);
		}

		public static string Localize(this ViewMasterPage master, string key, string defaultContent, ERPStore.Models.LocalizedContentType contentType)
		{
			var language = master.Html.GetCurrentLanguage();
			var path = GetVirtualPath(master);
			var localizationService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.ILocalizationService>();
			var token = master.ViewContext.HttpContext.Request["translate"];
			return localizationService.GetLocalizedContent(path, language, token, key, defaultContent, contentType);
		}


		/// <summary>
		/// Ajoute les element javascript pour la traduction en ligne des pages
		/// </summary>
		/// <param name="helper">The helper.</param>
		public static void LocalizationScript(this HtmlHelper helper)
		{
			string translate = helper.ViewContext.HttpContext.Request["translate"];
			if (translate != null)
			{
				helper.RenderAction("Script", "Localization");
			}
		}

		/// <summary>
		/// Retourne la langue courante
		/// </summary>
		/// <param name="helper">The helper.</param>
		/// <returns></returns>
		public static string GetCurrentLanguage(this HtmlHelper helper)
		{
			return (string)helper.ViewContext.HttpContext.Items["language"];
		}


		public static string GetCurrentLanguage(this UrlHelper helper)
		{
			return (string)helper.RequestContext.HttpContext.Items["language"];
		}

		/// <summary>
		/// Traduction d'une propriété d'une entité localizable
		/// </summary>
		/// <param name="localizableEntity">The localizable entity.</param>
		/// <param name="propertyExpresssion">The property expresssion.</param>
		/// <param name="language">The language.</param>
		/// <returns></returns>
		public static string Localize(this ERPStore.Models.ILocalizable localizableEntity, Expression<Func<string>> propertyExpresssion, string language)
		{
			string propertyName = null;
			string defaultValue;
			ExtractPropertyNameAndValue(localizableEntity, propertyExpresssion, out propertyName, out defaultValue);
			if (localizableEntity.LocalizationList.IsNullOrEmpty())
			{
				return defaultValue;
			}

			var result = localizableEntity.LocalizationList.FirstOrDefault(i => i.PropertyName.Equals(propertyName, StringComparison.InvariantCultureIgnoreCase)
																			&& i.Language.Name.Equals(language, StringComparison.InvariantCultureIgnoreCase));


			return result != null ? result.Value : defaultValue.ToString();
		}

		public static string LocalizedHref(this UrlHelper helper, ERPStore.Models.ProductCategory productCategory)
		{
			string link = productCategory.Localize(() => productCategory.Link, helper.GetCurrentLanguage());
			return helper.RouteERPStoreUrl(ERPStore.Web.Routing.ERPStoreRoutes.PRODUCT_BY_CATEGORY, new { link = link, });
		}

		public static string LocalizedHref(this UrlHelper helper, ERPStore.Models.Product product)
		{
			var link = (product.Link.IsNullOrTrimmedEmpty()) ? ERPStore.Web.Extensions.SEOHelper.SEOUrlEncode(product.Localize(() => product.Title, helper.GetCurrentLanguage())) : product.Localize(() => product.Link, helper.GetCurrentLanguage());
			return helper.RouteERPStoreUrl(ERPStoreRoutes.PRODUCT, new { code = product.Code, name = link });
		}

		private static void ExtractPropertyNameAndValue<T>(object entity, Expression<Func<T>> propertyExpresssion, out string propertyName, out T value)
		{
			if (propertyExpresssion == null)
			{
				throw new ArgumentNullException("propertyExpression");
			}

			var memberExpression = propertyExpresssion.Body as MemberExpression;
			if (memberExpression == null)
			{
				throw new ArgumentException("The expression is not a member access expression.", "propertyExpression");
			}

			var property = memberExpression.Member as System.Reflection.PropertyInfo;
			if (property == null)
			{
				throw new ArgumentException("The member access expression does not access a property.", "propertyExpression");
			}

			if (!property.DeclaringType.IsAssignableFrom(entity.GetType()))
			{
				throw new ArgumentException("The referenced property belongs to a different type.", "propertyExpression");
			}

			var getMethod = property.GetGetMethod(true);
			if (getMethod == null)
			{
				// this shouldn't happen - the expression would reject the property before reaching this far
				throw new ArgumentException("The referenced property does not have a get method.", "propertyExpression");
			}

			if (getMethod.IsStatic)
			{
				throw new ArgumentException("The referenced property is a static property.", "propertyExpression");
			}

			value = (T)property.GetValue(entity, null);
			propertyName = memberExpression.Member.Name;
		}

		private static string GetVirtualPath(object control)
		{
			string result = null;
			var templateControl = control as TemplateControl;
			if (templateControl != null)
			{
				result = templateControl.AppRelativeVirtualPath;
			}
			return result;
		}
	}
}
